package com.jsmile.cloud.msgcenter.web.config;

import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayConstants;
import com.alipay.api.DefaultAlipayClient;
import com.egzosn.pay.ali.api.AliPayConfigStorage;
import com.egzosn.pay.ali.api.AliPayService;
import com.egzosn.pay.common.api.PayService;
import com.egzosn.pay.common.bean.CertStoreType;
import com.egzosn.pay.common.http.HttpConfigStorage;
import com.egzosn.pay.wx.api.WxPayConfigStorage;
import com.egzosn.pay.wx.api.WxPayService;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.jsmile.cloud.accountcenter.api.enums.PayTypeEnum;
import com.jsmile.cloud.msgcenter.api.exception.MsgException;
import com.jsmile.cloud.msgcenter.pay.model.PayInfo;
import com.jsmile.cloud.msgcenter.pay.repo.PayInfoSearchRepository;
import com.jsmile.cloud.msgcenter.zf.handler.WxPayMessageHandler;
import com.jsmile.cloud.msgcenter.zf.handler.ZfbPayMessageHandler;
import com.jsmile.cloud.msgcenter.zf.req.ali.AliPayInfo;
import com.jsmile.mall.cache.kit.SpringKit;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;

/**
 * 微信服务配置
 */
@Slf4j
@Component
public class PayConfig implements CommandLineRunner {

    // TODO 小程序服务
    public static Map<String, WxMaService> maServices = Maps.newHashMap();
    // TODO 公众号服务
    public static Map<String, WxMpService> mpServices = Maps.newHashMap();

    // TODO 支付服务
    public static Map<String, PayService> payServices = Maps.newHashMap();

    // 支付宝服务
    private static Map<String, AliPayInfo> aliServices = Maps.newHashMap();

    /**
     * 获取微信支付service
     */
    public static AliPayInfo getAliService(String appid) {
        AliPayInfo aliPayInfo = aliServices.get(appid);
        if (aliPayInfo == null) {
            throw new MsgException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        return aliPayInfo;
    }

    /**
     * 获取微信支付service
     */
    public static PayService getPayService(String appid, int payType) {
        PayService payService = payServices.get(appid + "," + payType);
        if (payService == null) {
            throw new MsgException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        return payService;
    }

    /**
     * 获取微信公众号用户信息service
     */
    public static WxMpService getMpService(String appid) {
        WxMpService wxService = mpServices.get(appid);
        if (wxService == null) {
            throw new MsgException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        return wxService;
    }

    /**
     * 获取微信小程序用户信息service
     */
    public static WxMaService getMaService(String appid) {
        WxMaService wxService = maServices.get(appid);
        if (wxService == null) {
            throw new MsgException(String.format("未找到对应appid=[%s]的配置，请核实！", appid));
        }
        return wxService;
    }

    // TODO 添加微信公众号和小程序服务service
    public static void putWxService(PayInfo payInfo) {
        if (PayTypeEnum.WX_JS.getValue() == payInfo.getPayType()) {
            WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
            config.setAppid(payInfo.getAppId());
            config.setSecret(payInfo.getAppSecret());
            config.setMsgDataFormat("JSON");
            WxMaService service = new WxMaServiceImpl();
            service.setWxMaConfig(config);
            PayConfig.maServices.put(payInfo.getAppId(), service);
        } else if (PayTypeEnum.WX_H5.getValue() == payInfo.getPayType()) {
            WxMpService wxMpService = new WxMpServiceImpl();
            WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
            configStorage.setAppId(payInfo.getAppId());
            configStorage.setSecret(payInfo.getAppSecret());
            wxMpService.setWxMpConfigStorage(configStorage);
            PayConfig.mpServices.put(payInfo.getAppId(), wxMpService);
        }
    }

    public static void putAliService(PayInfo payInfo) {
        AliPayInfo aliPayInfo = AliPayInfo.builder().appId(payInfo.getAppId()).appPrivateKey(payInfo.getPrivateKey()).alipayPublicKey(payInfo.getPayPublicKey())
            .aesKey(payInfo.getAesKey()).authToken(payInfo.getAuthToken()).build();

        log.info("signVeriKey:{};\ndecryptKey:{}", aliPayInfo.getAlipayPublicKey(), aliPayInfo.getAppPrivateKey());
        if (Stream.of(payInfo.getPrivateKey(), payInfo.getPublicKey()).noneMatch(Strings::isNullOrEmpty)) {
            DefaultAlipayClient alipayClient = new DefaultAlipayClient(aliPayInfo.getUrl(), aliPayInfo.getAppId(), aliPayInfo.getAppPrivateKey(), aliPayInfo.getFormat(),
                aliPayInfo.getCharset(), aliPayInfo.getAlipayPublicKey(), aliPayInfo.getSignType(), aliPayInfo.getAesKey(), AlipayConstants.ENCRYPT_TYPE_AES);
            aliPayInfo.setClient(alipayClient);
        } else {
            log.error("-----没有私钥或支付宝公钥，无法生成客户端");
        }
        PayConfig.aliServices.put(payInfo.getAppId(), aliPayInfo);
        log.info("创建支付宝网关访问客户端完成, 网关地址：{}，appId:{}", aliPayInfo.getUrl(), aliPayInfo.getAppId());
    }

    @Override
    public void run(String... args) throws Exception {
        List<PayInfo> pays = SpringKit.getBean(PayInfoSearchRepository.class).list();
        log.info("微信配置信息：{}", JSON.toJSONString(pays));
        pays.forEach(payInfo -> {
            PayConfig.payServices.put(payInfo.getAppId() + "," + payInfo.getPayType(), getPayService(payInfo));
            PayConfig.putWxService(payInfo);
            PayConfig.putAliService(payInfo);
        });
    }

    // TODO 获取支付服务
    public PayService getPayService(PayInfo payInfo) {
        if (PayTypeEnum.hasWxPay(payInfo.getPayType())) {
            return getWxPayService(payInfo);
        } else if (PayTypeEnum.hasZfbPay(payInfo.getPayType())) {
            return getZfbPayService(payInfo);
        }
        return null;
    }

    // TODO 微信支付
    public PayService getWxPayService(PayInfo payInfo) {
        WxPayConfigStorage wxPayConfigStorage = new WxPayConfigStorage();
        wxPayConfigStorage.setAppId(StringUtils.trimToNull(payInfo.getAppId()));
        wxPayConfigStorage.setMchId(StringUtils.trimToNull(payInfo.getMchId()));
        wxPayConfigStorage.setSecretKey(StringUtils.trimToNull(payInfo.getMchSecret()));
        wxPayConfigStorage.setNotifyUrl(StringUtils.trimToNull(payInfo.getNotifyUrl()) + "?thirdAppId=" + payInfo.getAppId() + "&thirdPayType=" + payInfo.getPayType());
        wxPayConfigStorage.setReturnUrl(StringUtils.trimToNull(payInfo.getReturnUrl()));
        wxPayConfigStorage.setSignType(StringUtils.trimToNull(payInfo.getSignType()));
        wxPayConfigStorage.setInputCharset("utf-8");

        HttpConfigStorage httpConfigStorage = new HttpConfigStorage();
        httpConfigStorage.setKeystore(new ByteArrayInputStream(payInfo.getCertData()));
        // 设置ssl证书对应的存储方式，这里默认为文件地址
        httpConfigStorage.setCertStoreType(CertStoreType.INPUT_STREAM);
        WxPayService payService = new WxPayService(wxPayConfigStorage);
        payService.setPayMessageHandler(SpringKit.getBean(WxPayMessageHandler.class));
        return payService;

    }

    // TODO 支付宝支付
    public PayService getZfbPayService(PayInfo payInfo) {
        AliPayConfigStorage aliPayConfigStorage = new AliPayConfigStorage();
        // aliPayConfigStorage.setPid(payInfo.getMchId());
        aliPayConfigStorage.setAppid(StringUtils.trimToNull(payInfo.getAppId()));
        aliPayConfigStorage.setKeyPublic(payInfo.getPublicKey());
        aliPayConfigStorage.setKeyPrivate(payInfo.getPrivateKey());
        aliPayConfigStorage.setNotifyUrl(StringUtils.trimToNull(payInfo.getNotifyUrl()) + "?thirdAppId=" + payInfo.getAppId() + "&thirdPayType=" + payInfo.getPayType());
        aliPayConfigStorage.setReturnUrl(StringUtils.trimToNull(payInfo.getReturnUrl()));
        aliPayConfigStorage.setSignType(StringUtils.trimToNull(payInfo.getSignType()));
        // aliPayConfigStorage.setSeller("收款账号");
        aliPayConfigStorage.setInputCharset("utf-8");
        // 是否为测试账号，沙箱环境
        // aliPayConfigStorage.setTest(true);

        // 请求连接池配置
        HttpConfigStorage httpConfigStorage = new HttpConfigStorage();
        // 最大连接数
        httpConfigStorage.setMaxTotal(20);
        // 默认的每个路由的最大连接数
        httpConfigStorage.setDefaultMaxPerRoute(10);

        PayService aliPayService = new AliPayService(aliPayConfigStorage, httpConfigStorage);
        // 以下拦截器与处理器用于支付与业务隔离简化版回调
        // 增加支付回调消息拦截器
        // aliPayService.addPayMessageInterceptor(new AliPayMessageInterceptor());
        // 设置回调消息处理
        aliPayService.setPayMessageHandler(SpringKit.getBean(ZfbPayMessageHandler.class));
        return aliPayService;
    }
}
